<?php
namespace GrouppaGroup;

require_once 'MessageFromApp.php';
require_once 'ErrorMessage.php';
require_once 'Settings.php';
require_once 'Db.php';

/**
 * @abstract
 */
class Controller
{
    /**
     * receives a message from an application
     * @param MessageFromApp $message
     * @abstract
     */
    public function receiveMessage(MessageFromApp $message)
    {
        //this method should be overwritten
        throw new \Exception("Controller::receiveMessage: unsupported method");
    }

    /**
     * Is the user logged in?
     * @var boolean
     */
    private static $userLoggedIn = false;

    /**
     * Sends message back to the user with message rejection and reasononing
     * @param MessageFromApp $message
     * @param string         $reason
     */
    private static function sendAccessRejectedMessage(MessageFromApp $message, $reason)
    {
        //CHECK: send error message to user with rejection
        $response = new ErrorMessage($reason, 'errorAccess', 'System', $message->id);
        ApplicationTCPConnection::sendMessage($response);
    }

    /**
     * Checks if the user is logged in
     * @param  MessageFromApp $message
     * @return boolean        true iff user is logged in
     */
    protected static function checkAccess(MessageFromApp $message)
    {
        //CHECK: check access for the user

        if (self::$userLoggedIn) {
            return true;
        }

        $accessToken = $message->accessToken;

        if (!$accessToken) {
            self::sendAccessRejectedMessage($message, "no access token supplied");

            return false;
        }

        $db = Db::getInstance();

        $check = $db->sendQuery('SELECT id_user,access_token_valid_to FROM users WHERE user_name="' .
            $message->from . '" AND access_token="' . $accessToken . '";');

        if ($check->num_rows == 0) { // wrong access token or
            self::sendAccessRejectedMessage($message,
                'wrong access token or user non existent');

            return false;
        }

        $row = $check->fetch_row();
        $accessTokenValidity = $row[1];
        $now = strtotime("now");

        if (USER_ACCESS_TOKEN_CHECK_VALIDITY && $accessTokenValidity < $now) {
            self::sendAccessRejectedMessage($message, 'access token timed out');

            return false;
        }

        self::$userLoggedIn = true;

        $accessTokenValidity = $now + USER_ACCESS_TOKEN_TIME;
        $db->sendQuery('UPDATE users SET access_token_valid_to=' . $accessTokenValidity .
            ' WHERE id_user=' . $row[0]);

        $check->free();

        return true;
    }

    /**
     * Call if client requested an unknown task from the controller
     * will send error in response
     * @param MessageFromApp $message        message that requested the task
     * @param string         $controllerName name of the controller
     */
    protected static function unknownTask(MessageFromApp $message, $controllerName)
    {
        //CHECK: send error message informing about unknown task
        $response = new ErrorMessage('client requested an unknown task from the controller',
            $message->messageType, $controllerName, $message->id);

        ApplicationTCPConnection::sendMessage($response);
    }

    /**
     * checks if the user is the manager of specified group
     * @param  string  $groupName name of the group to check
     * @param  string  $userName  name of the user to check
     * @return boolean true iff $userName is the manager of group $groupName
     */
    public static function isManager($groupName, $userName)
    {

        //CHECKED: checks if the user is the manager of the group
        $db = Db::getInstance();
        $result = $db->sendQuery('SELECT users.id_user FROM group_managers
                INNER JOIN users ON group_managers.id_user=users.id_user
                INNER JOIN groups ON group_managers.id_group = groups.id_group
                WHERE users.user_name="'.$userName.'" AND groups.group_name="'.$groupName.'"');
        $isManager = $result->num_rows==1;
        $result->free();

        return $isManager;

    }

    /**
     * gets id of a user with specified name
     * @param  string  $userName name of the user
     * @return integer id of the user
     */
    public static function getUserId($userName)
    {

        $db = Db::getInstance();
        $result = $db->sendQuery('SELECT users.id_user FROM users
                WHERE users.user_name="'.$userName.'";');
        if ($result->num_rows == 0) {
            throw new \Exception('Controller:getUserId: user '.$userName.' not found');
        }
        $userId = $result->fetch_row()[0];
        $result->free();

        return $userId;
    }
    /**
     * gets id of a group with specified name
     * @param  string  $groupName name of the group
     * @return integer id of the group
     */
    public static function getGroupId($groupName)
    {

        $db = Db::getInstance();
        $result = $db->sendQuery('SELECT groups.id_group FROM groups
                WHERE groups.group_name="'.$groupName.'";');
        if ($result->num_rows == 0) {
            throw new \Exception('Controller:getGroupId: group '.$groupName.' not found');
        }
        $groupId = $result->fetch_row()[0];
        $result->free();

        return $groupId;
    }
}
